package com.kedll.library.adapter;

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by QiQi on 2017/1/23.
 */

public class WrapAdapter<T extends RecyclerView.Adapter> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int BASE_HEADER_VIEW_TYPE = -1 << 10;
    private static final int BASE_FOOTER_VIEW_TYPE = -1 << 11;

    private final T mRealAdapter;
    private boolean isStaggeredGrid;

    private List<FixedViewInfo> mHeadViewList = new ArrayList<>();
    private List<FixedViewInfo> mFootViewList = new ArrayList<>();

    public WrapAdapter(T adapter) {
        super();
        this.mRealAdapter = adapter;
    }

    /**
     * Called when RecyclerView needs a new {@link RecyclerView.ViewHolder} of the given type to represent
     * an item.
     * <p>
     * This new ViewHolder should be constructed with a new View that can represent the items
     * of the given type. You can either create a new View manually or inflate it from an XML
     * layout file.
     * <p>
     * The new ViewHolder will be used to display items of the adapter using
     * {@link #onBindViewHolder(RecyclerView.ViewHolder, int, List)}. Since it will be re-used to display
     * different items in the data set, it is a good idea to cache references to sub views of
     * the View to avoid unnecessary {@link View#findViewById(int)} calls.
     *
     * @param parent   The ViewGroup into which the new View will be added after it is bound to
     *                 an adapter position.
     * @param viewType The view type of the new View.
     * @return A new ViewHolder that holds a View of the given view type.
     * @see #getItemViewType(int)
     * @see #onBindViewHolder(RecyclerView.ViewHolder, int)
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (isHeader(viewType)) {
            int whichHeader = Math.abs(viewType - BASE_HEADER_VIEW_TYPE);
            View headerView = mHeadViewList.get(whichHeader).view;
            return createHeaderFooterViewHolder(headerView);
        } else if (isFooter(viewType)) {
            int whichFooter = Math.abs(viewType - BASE_FOOTER_VIEW_TYPE);
            View footerView = mFootViewList.get(whichFooter).view;
            return createHeaderFooterViewHolder(footerView);
        } else {
            return mRealAdapter.onCreateViewHolder(parent, viewType);
        }
    }

    /**
     * Called by RecyclerView to display the data at the specified position. This method should
     * update the contents of the {@link RecyclerView.ViewHolder#itemView} to reflect the item at the given
     * position.
     * <p>
     * Note that unlike {@link ListView}, RecyclerView will not call this method
     * again if the position of the item changes in the data set unless the item itself is
     * invalidated or the new position cannot be determined. For this reason, you should only
     * use the <code>position</code> parameter while acquiring the related data item inside
     * this method and should not keep a copy of it. If you need the position of an item later
     * on (e.g. in a click listener), use {@link RecyclerView.ViewHolder#getAdapterPosition()} which will
     * have the updated adapter position.
     * <p>
     * Override {@link #onBindViewHolder(RecyclerView.ViewHolder, int, List)} instead if Adapter can
     * handle efficient partial bind.
     *
     * @param holder   The ViewHolder which should be updated to represent the contents of the
     *                 item at the given position in the data set.
     * @param position The position of the item within the adapter's data set.
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (position < mHeadViewList.size()) {

        } else if (position < mHeadViewList.size() + mRealAdapter.getItemCount()) {
            mRealAdapter.onBindViewHolder(holder, position - mHeadViewList.size());
        } else {

        }
    }

    /**
     * Returns the total number of items in the data set held by the adapter.
     *
     * @return The total number of items in this adapter.
     */
    @Override
    public int getItemCount() {
        return mHeadViewList.size() + mRealAdapter.getItemCount() + mFootViewList.size();
    }

    /**
     * Add the headerView
     *
     * @param view headerView
     */
    public void addHeadView(View view) {
        if (view == null) {
            throw new IllegalArgumentException("the view to add must not be null");
        }
        final FixedViewInfo info = new FixedViewInfo();
        info.view = view;
        info.viewType = BASE_HEADER_VIEW_TYPE + mHeadViewList.size();
        mHeadViewList.add(info);
        notifyDataSetChanged();
    }

    /**
     * Add the footerView
     *
     * @param view footerView
     */
    public void addFootView(View view) {
        if (view == null) {
            throw new IllegalArgumentException("the view to add must not be null");
        }
        final FixedViewInfo info = new FixedViewInfo();
        info.view = view;
        info.viewType = BASE_FOOTER_VIEW_TYPE + mFootViewList.size();
        mFootViewList.add(info);
        notifyDataSetChanged();
    }

    public void adjustSpanSize(RecyclerView recycler) {
        if (recycler.getLayoutManager() instanceof GridLayoutManager) {
            final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
            layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    boolean isHeaderOrFooter = isHeaderPosition(position) || isFootPosition(position);
                    return isHeaderOrFooter ? layoutManager.getSpanCount() : 1;
                }
            });
        }

        if (recycler.getLayoutManager() instanceof StaggeredGridLayoutManager) {
            this.isStaggeredGrid = true;
        }
    }

    private boolean isFootPosition(int position) {
        return position >= mHeadViewList.size() + mRealAdapter.getItemCount();
    }

    private boolean isHeaderPosition(int position) {
        return position < mHeadViewList.size();
    }

    public void setFooterVisibility(boolean shouldShow) {
        for (FixedViewInfo info : mFootViewList) {
            info.view.setVisibility(shouldShow ? View.VISIBLE : View.GONE);
        }

        notifyDataSetChanged();
    }

    private boolean isHeader(int viewType) {
        return viewType >= BASE_HEADER_VIEW_TYPE && viewType < (BASE_HEADER_VIEW_TYPE + mHeadViewList.size());
    }

    private boolean isFooter(int viewType) {
        return viewType >= BASE_FOOTER_VIEW_TYPE && viewType < (BASE_FOOTER_VIEW_TYPE + mFootViewList.size());
    }

    public int getHeadCount() {
        return mHeadViewList.size();
    }

    public int getFootCount() {
        return mFootViewList.size();
    }

    public T getWrappedAdapter() {
        return mRealAdapter;
    }

    @Override
    public int getItemViewType(int position) {
        if (isHeaderPosition(position)) {
            return mHeadViewList.get(position).viewType;
        } else if (isFootPosition(position)) {
            return mFootViewList.get(position - mHeadViewList.size() - mRealAdapter.getItemCount()).viewType;
        } else {
            return mRealAdapter.getItemViewType(position - mHeadViewList.size());
        }
    }

    private RecyclerView.ViewHolder createHeaderFooterViewHolder(View view) {
        if (isStaggeredGrid) {
            StaggeredGridLayoutManager.LayoutParams params = new StaggeredGridLayoutManager.LayoutParams(StaggeredGridLayoutManager.LayoutParams.MATCH_PARENT,
                    StaggeredGridLayoutManager.LayoutParams.WRAP_CONTENT);
            params.setFullSpan(true);
            view.setLayoutParams(params);
        }
        return new RecyclerView.ViewHolder(view) {
        };
    }

    static class FixedViewInfo {
        public View view;
        public int viewType;
    }
}
